#include "Spec.h"

#include "ListeSorts.h"

using namespace std;
using namespace boost::assign;

const unsigned int Spec::nbr_comp = 35;

const unsigned int Spec::nbr_restric = 5;

const unsigned int Spec::nbr_restricUI = 2;

const unsigned int Spec::nbr_spec = 20;

const unsigned int Spec::nbr_ecoles = 7; 

/**
 * Contient les écoles de philosophie, les écoles d'effets et
 * les écoles de thaumaturgie.
 */
const vector< vector< unsigned int > > Spec::ecoles_magie =
  list_of< vector< unsigned int > >
  ( list_of(1)(3)(4)(5)(7)(8) ) // Abjurateur
  ( list_of(1)(2)(3)(4)(6)(8) ) // Conjurateur
  ( list_of(1)(2)(3)(4)(5)(7) ) // Divinateur
  ( list_of(1)(2)(3)(4)(5)(6) ) // Enchanteur
  ( list_of(2)(3)(4)(5)(6) ) // Illusionniste
  ( list_of(1)(2)(5)(6)(7)(8) ) // Evocateur
  ( list_of(1)(2)(3)(5)(7)(8) ) // Nécromancien
  ( list_of(2)(3)(4)(5)(6)(7) ) // Transmutateur
  ( list_of(12)(13)(14) ) // Elementaliste de l'Air
  ( list_of(13)(12)(15) ) // Elementaliste de l'Eau
  ( list_of(14)(12)(15) ) // Elementaliste du Feu
  ( list_of(15)(13)(14) ) // Elementaliste de Terre
  ( list_of(1)(2)(3)(5)(6)(7)(11) ) // Dimensionnaliste
  ( list_of(1)(3)(4)(6)(7)(8)(17) ) // Mage des Forces
  ( list_of(2)(3)(4)(5)(6)(8)(20) ) // Mage des Ombres
  ( list_of(1)(2)(3)(4)(5)(7)(9) ) // Alchimiste
  ( list_of(1)(2)(3)(5)(6)(7)(10) ) // Artificier
  ( list_of(1)(2)(3)(4)(5)(16) ) // Eurythmicien
  ( list_of(1)(2)(3)(5)(7)(8)(18) ) // Géométricien
  ( list_of(1)(2)(3)(4)(5)(6)(19) ); // Mentaliste
  /*
  { 
    // Ecoles de philosophie
    { 1,  3,  4,  5,  7,  8,  0}, // Abjurateur
    { 1,  2,  3,  4,  6,  8,  0}, // Conjurateur
    { 1,  2,  3,  4,  5,  7,  8}, // Divinateur
    { 1,  2,  3,  4,  5,  6,  0}, // Enchanteur
    { 2,  3,  4,  5,  6,  0,  0}, // Illusionniste
    { 1,  2,  5,  6,  7,  8,  0}, // Evocateur
    { 1,  2,  3,  5,  7,  8,  0}, // Nécromancien
    { 2,  3,  4,  5,  6,  7,  0}, // Transmutateur

    // Ecoles d'effets
    {12, 13, 14,  0,  0,  0,  0}, // Elementaliste de l'Air
    {13, 12, 15,  0,  0,  0,  0}, // Elementaliste de l'Eau
    {14, 12, 15,  0,  0,  0,  0}, // Elementaliste du Feu
    {15, 13, 14,  0,  0,  0,  0}, // Elementaliste de Terre
    { 1,  2,  3,  5,  6,  7, 11}, // Dimensionnaliste
    { 1,  3,  4,  6,  7,  8, 17}, // Mage des Forces
    { 2,  3,  4,  5,  6,  8, 20}, // Mage des Ombres

    // Ecoles de thaumaturgie
    { 1,  2,  3,  4,  5,  7,  9}, // Alchimiste
    { 1,  2,  3,  5,  6,  7, 10}, // Artificier
    { 1,  2,  3,  4,  5, 16,  0}, // Eurythmicien
    { 1,  2,  3,  5,  7,  8, 18}, // Géométricien
    { 1,  2,  3,  4,  5,  6, 19}  // Mentaliste
  };
*/
const vector<ListComp> Spec::Comp = list_of
  (ListComp("Abjuration"               ,  5))
  (ListComp("Altération"               ,  5))
  (ListComp("Conjuration - Convocation",  5))
  (ListComp("Divination"               ,  5))
  (ListComp("Enchantement - Charme"    ,  5))
  (ListComp("Illusion - Fantasme"      ,  5))
  (ListComp("Invocation - Evocation"   ,  5))
  (ListComp("Nécromancie"              ,  5))
  (ListComp("Alchimie"                 ,  5))
  (ListComp("Artifices"                ,  5))
  (ListComp("Dimension"                ,  5))
  (ListComp("Elémentaire - Air"        ,  5))
  (ListComp("Elémentaire - Eau"        ,  5))
  (ListComp("Elémentaire - Feu"        ,  5))
  (ListComp("Elémentaire - Terre"      ,  5))
  (ListComp("Eurythmique"              ,  5))
  (ListComp("Forces"                   ,  5))
  (ListComp("Géométrie"                ,  5))
  (ListComp("Mentalisme"               ,  5))
  (ListComp("Ombres"                   ,  5))
  (ListComp("Bonus à l'étude"          ,  5))
  (ListComp("Bonus à la recherche"     ,  5))
  (ListComp("Bonus aux JS"             ,  5))
  (ListComp("Dés de vie à 1d6"         , 10))
  (ListComp("Détection de la magie"    , 10))
  (ListComp("Durées de sorts acrues"   , 10))
  (ListComp("Incantation rapide"       ,  5))
  (ListComp("Lecture de la magie"      , 10))
  (ListComp("Mage combattant"          , 10))
  (ListComp("Mage en armure"           , 15))
  (ListComp("Magie intense"            ,  5))
  (ListComp("Pas de composantes"       , 10))
  (ListComp("Portée accrue"            , 10))
  (ListComp("Sort automatique"         ,  5))
  (ListComp("Sorts supplémentaires"    , 10));

const vector<ListComp> Spec::Restric = list_of
  (ListComp("Malus à l'étude"                             , 5))
  (ListComp("Lim : potions, huiles et parchemins"         , 5))
  (ListComp("Lim : anneau, de bâton, bâtonnet et baguette", 5))
  (ListComp("Lim : armes et armures magiques"             , 5))
  (ListComp("Ecoles supplémentaires en opposition"        , 5));

const vector< ListCapa > Spec::quel_spec = list_of
  ( ListCapa("Abjurateur") )
  ( ListCapa("Conjurateur") )
  ( ListCapa("Divinateur") )
  ( ListCapa("Enchanteur") )
  ( ListCapa("Illusioniste") )
  ( ListCapa("Invocateur") )
  ( ListCapa("Nécromancien") )
  ( ListCapa("Transmutateur") )
  ( ListCapa("Mage de l'Air") )
  ( ListCapa("Mage de l'Eau") )
  ( ListCapa("Mage du Feu") )
  ( ListCapa("Mage de Terre") )
  ( ListCapa("Dimensionnaliste") )
  ( ListCapa("Mage des Forces") )
  ( ListCapa("Mage des Ombres") )
  ( ListCapa("Alchimiste") )
  ( ListCapa("Artificier") )
  ( ListCapa("Eurythmicien") )
  ( ListCapa("Géométricien") )
  ( ListCapa("Mentaliste") );

const vector< vector< Prerequis > > Spec::Limites = 
  list_of< vector< Prerequis > >
  ( list_of( Prerequis(4, 15) ) ) // Abjurateur
  ( list_of( Prerequis(2, 15) ) ) // Conjurateur
  ( list_of( Prerequis(4, 16) ) ) // Divinateur
  ( list_of( Prerequis(5, 16) ) ) // Enchanteur
  ( list_of( Prerequis(1, 16) ) ) // Illusionniste
  ( list_of( Prerequis(2, 16) ) ) // Evocateur
  ( list_of( Prerequis(4, 16) ) ) // Nécromancien
  ( list_of( Prerequis(1, 15) ) ) // Transmutateur
  ( list_of( Prerequis(3,  9) ) ) // Elementaliste de l'Air
  ( list_of( Prerequis(3,  9) ) ) // Elementaliste de l'Eau
  ( list_of( Prerequis(3,  9) ) ) // Elementaliste du Feu
  ( list_of( Prerequis(3,  9) ) ) // Elementaliste de Terre
  ( list_of( Prerequis(3, 16) ) ) // Dimensionnaliste
  ( list_of( Prerequis(3, 12) )( Prerequis(2, 15) ) ) // Mage des Forces
  ( list_of( Prerequis(3, 15) )( Prerequis(4, 16) ) ) // Mage des Ombres
  ( list_of( Prerequis(3, 15) )( Prerequis(1, 14) ) ) // Alchimiste
  ( list_of( Prerequis(3, 12) )( Prerequis(2, 15) ) ) // Artificier
  ( list_of( Prerequis(3, 14) )( Prerequis(5, 15) ) ) // Eurythmicien
  ( list_of( Prerequis(3, 15) )( Prerequis(4, 14) ) ) // Géométricien
  ( list_of( Prerequis(3, 15) )( Prerequis(4, 16) ) );// Mentaliste

const vector< set< string > > Spec::RacesAdmises =
  list_of< set< string > >
  ( list_of("Humain") )                      // Abjurateur
  ( list_of("Humain")("Demi-Elfe") )         // Conjurateur
  ( list_of("Humain")("Demi-Elfe")("Elfe") ) // Divinateur
  ( list_of("Humain")("Demi-Elfe")("Elfe") ) // Enchanteur
  ( list_of("Humain")("Gnome") )             // Illusionniste
  ( list_of("Humain") )                      // Evocateur
  ( list_of("Humain") )                      // Nécromancien
  ( list_of("Humain")("Demi-Elfe") )         // Transmutateur
  ( list_of("Humain") )                      // Elementaliste de l'Air
  ( list_of("Humain") )                      // Elementaliste de l'Eau
  ( list_of("Humain") )                      // Elementaliste du Feu
  ( list_of("Humain") )                      // Elementaliste de Terre
  ( list_of("Humain")("Demi-Elfe") )         // Dimensionnaliste
  ( list_of("Humain")("Demi-Elfe") )         // Mage des Forces
  ( list_of("Humain") )                      // Mage des Ombres
  ( list_of("Humain") )                      // Alchimiste
  ( list_of("Humain")("Gnome") )             // Artificier
  ( list_of("Humain")("Demi-Elfe")("Elfe") ) // Eurythmicien
  ( list_of("Humain")("Demi-Elfe")("Elfe") ) // Géométricien
  ( list_of("Humain") );                     // Mentaliste

/** Constructeur usuel.
 * Permet la construction d'un spécialiste de A à Z, càd on détermine
 * ici les restrictions, puis les compétences.
 *
 * @param xp le nombre de pts d'expérience du Spécialiste.
 * @param trait les traits du Spécialiste, le 7ème contient le score
 * de force exceptionnel, fixé à 0 si non applicable.
 * @param PP nombre de points de personnage (PP) à disposition pour la
 * céation du Spécialiste.
 * @param race nom de la race du personnage.
 */
Spec::Spec(unsigned int xp, unsigned int trait[7], unsigned int& PP,
	   const string& race)
  : Classe(xp, trait, Magiciens, race)
{
  Type_classe = "Spécialiste";
  PP += 30;
  ptrComp       = &Comp;
  ptrRes        = &Restric;
  ptrNbrComp    = &nbr_comp;
  ptrNbrRes     = &nbr_restric;
  ptrNomEnsComp = &quel_spec;
  ptrNbrEns     = &nbr_spec;
  ptrMaxEns     = &nbr_ecoles;
  blank() << setfill('*') << setw(56) << '*' << setfill(' ') << endreq;
  blank() << "Création d'un mage spécialiste" << endreq << endl;
  for (unsigned int i(0); i < nbr_spec; i++) // /!\ taille
    blank() << i+1 << ' ' << quel_spec[i] . Capa << endreq;
  blank() << endreq;

  unsigned int nbr(0);

  nbr = demanderUnsignedBorne("Choisissez le type de spécialiste ", 1,
				nbr_spec + 1);
  blank() << endreq;

  if (ecoles_magie[nbr-1][0] > 10)
    // Il s'agit d'un élémentaliste
    {
      debug() << "Elémentaliste" << endreq;
      for (unsigned int j(0); j < 8; j++)
	{
	  Comp_classe.push_back(j);
	  debug() << "Ajout de " << Comp[Comp_classe.back()].Comp << endreq;
	}
    }

  for (unsigned int i(0); i < nbr_ecoles; i++)
    {
      if (ecoles_magie[nbr-1][i] != 0)
	Comp_classe.push_back(ecoles_magie[nbr-1][i]-1);
	  debug() << "Ajout de " << Comp[Comp_classe.back()].Comp << endreq;
    }

  for (unsigned int i(0); i < nbr_restric; i++)
    {
      if (Restric[i].Cout != 0)
	blank() << i+1 << ' ' << Restric[i].Comp << " ("
		    << Restric[i].Cout << " pp)" << endreq;
      else
	blank() << i+1 << ' ' << Restric[i].Comp << " cout variable"
		    << endreq;	
    }
  blank() << nbr_restric+1 << " Aucune" << endreq;

  bool test(true), deja_pris, encore(false);
  unsigned int save_PP(PP);

  do
    {
      do
	{
	  nbr = demanderUnsignedBorne("Choisir les restrictions ", 1,
					nbr_restric + 1);
	  
	  if (nbr != nbr_restric+1)
	    {
	      if (Restric[nbr-1].Cout == 0)
		{
		  deja_pris = safePushBack(&Comp_classe, nbr_comp + 1 + nbr);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr_comp +  nbr - 1);
		      unsigned int pps;
		      pps =  demanderUnsigned("Entrez les PP obtenus : ");
		      PP += pps;
		      blank() << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		}
	      else
		{
		  deja_pris = safePushBack(&Comp_classe, nbr_comp + 1 + nbr);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr_comp + nbr - 1);
		      PP += Restric[nbr-1].Cout;
		      blank() << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		  if (nbr == 3)
		    {
		      unsigned int combien(Comp_classe.size()), laquelle;
		      for (unsigned int i(0); i < combien; i++)
			{
			  if (Comp_classe[i] < 20)
			    blank() << setw(2) << i + 1 << ' ' 
					<< Comp[Comp_classe[i]].Comp << endreq;
			}
		      blank() << combien + 1 << endreq;
		      
		      laquelle =
			demanderUnsignedBorne("Entrez l'école en opposition supplémentaire", 1, combien);
		      
		      if (laquelle == combien + 1)
			blank() << "Annulation" << endreq;
		      else
			{
			  linfo() << "Suppression de " << Comp[Comp_classe[laquelle - 1]].Comp << " en cours" << endreq;
			  vector<unsigned int>::iterator it(Comp_classe.begin()), End(Comp_classe.end());
			  debug() << "Avant suppression = " << (unsigned int) (End - it) << endreq;
			  while(*it != laquelle - 1)
			    it++;
			  Comp_classe.erase(it);
			  debug() << "Après suppression = " << (unsigned int) (Comp_classe.end() - Comp_classe.begin()) << endreq;
			}
		      
		    }
		}
	    }
	  else
	    test = false;
	}
      while(test);

      afficheCompetences();
      blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demanderUnsignedBorne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  Comp_classe.clear();
	  test = true;
	  encore = true;
	  blank() << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  test = true;

  blank() << "Tu as " << PP << " pp à dépenser" << endreq;
  save_PP = PP;

  for (unsigned int i(20); i < nbr_comp; i++)
    {
      if (Comp[i].Cout != 0)
	blank() << i+1 << ' ' << Comp[i].Comp << " (" << Comp[i].Cout
		    << " pp)" << endreq;
      else
	blank() << i+1 << ' ' << Comp[i].Comp << " (cout variable)"
		    << endreq;	
    }
  blank() << nbr_comp+1 << " Aucune" << endreq;
  blank() << "Choisir les compétences de classe" << endreq;

  test = true;

  do
    {
      do
	{
	  nbr = demanderUnsignedBorne("("+ecrireString(PP)+" restants) ", 20,
					nbr_comp + 1);
	  if (nbr!=nbr_comp+1)
	    {
	      if (PP >= Comp[nbr-1].Cout)
		{
		  deja_pris = safePushBack(&Comp_classe, nbr - 1);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr-1);
		      PP -= Comp[nbr-1].Cout;
		      blank() << "Compétence choisie : " << Comp[nbr-1].Comp
				  << endreq;
		    }
		}
	      else
		blank() << "Pas assez de pp" << endreq;
	    }
	  else
	    test = false;
	}
      while(test);

      afficheCompetences();
      blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demanderUnsignedBorne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  while(Comp_classe.back() < nbr_comp)
	    Comp_classe.pop_back();
	  test = true;
	  encore = true;
	  blank() << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  blank() << endl << setfill('*') << setw(56) << '*' << endreq;
  calculNiveau();
  calculNivMag();
}

/** Constructeur simplifié.
 * Permet de construire un Spécialiste lors de la lecture d'un fichier xml.
 * @param xp le nombre de pts d'expérience du Spécialiste.
 * @param trait les traits du Spécialiste, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param race nom de la race du personnage.
 */
Spec::Spec(unsigned int xp, unsigned int trait[7], const string& race)
  : Classe(xp, trait, Magiciens, race)
{
  Type_classe = "Spécialiste";
  ptrComp       = &Comp;
  ptrRes        = &Restric;
  ptrNbrComp    = &nbr_comp;
  ptrNbrRes     = &nbr_restric;
  ptrNomEnsComp = &quel_spec;
  ptrNbrEns     = &nbr_spec;
  ptrMaxEns     = &nbr_ecoles;
  calculNiveau();
  calculNivMag();
}

/**  Constructeur pour le mode graphique.
 * Permet de construire une instance de Mage avec le contenu
 * minimal, le nombre de points d'expériences et les capacités étant
 * déterminées après la déclaration.
 *
 * @param trait les traits du Mage, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param UI contrôle, est présent pour des raisons historiques.
 * @param race nom de la race du personnage.
 */
Spec::Spec(unsigned int trait[7], const bool& UI, const string& race)
  : Classe(0, trait, Magiciens, race)
{
  if (!UI)
    {
      error() << "Création du personnage impossible" << endreq;
      exit(1);
    }

  Type_classe = "Spécialiste";

  ptrComp       = &Comp;
  ptrRes        = &Restric;
  ptrNbrComp    = &nbr_comp;
  ptrNbrRes     = &nbr_restricUI;
  ptrNomEnsComp = &quel_spec;
  ptrNbrEns     = &nbr_spec;
  ptrMaxEns     = &nbr_ecoles;

  calculNiveau();
  calculNivMag();
}

Spec::~Spec()
{}

void Spec::calculNiveau()
{
  if (XP < 60000)
    {
      unsigned int i;
      for (i = 0; i < 5; i++)
	{
	  if (XP < (unsigned int) 2500 * puissance(2, i))
	    break;
	}
      Niveau = i+1;
    }
  else if (XP < 90000)
    Niveau = 7;
  else if (XP < 135000)
    Niveau = 8;
  else if (XP < 250000)
    Niveau = 9;
  else if (XP < 375000)
    Niveau = 10;
  else if (XP < 750000)
    Niveau = 11;
  else
      Niveau = (XP - 750000) / 375000 + 12;
}

// void Spec::afficher_stats(ostream& os)
// {
//   os << Type_classe << endreq;
//   for (unsigned int i(0); i < 6; i++)
//     os << Caracteristiques[i] << ' ' << Traits[i] << endreq;
//   for (unsigned int i(0); i < Comp_classe.size(); i++)
//     os << get_competence(i) << endreq;
// }

// void Spec::appliquerModif(const string& type)
// {}

// void Spec::augmenterTalents(const unsigned int& bonus, const bool& lvl_up)
// {}

void Spec::getJS(unsigned int *tab) const
{
  *(tab + 0) = 14; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 11; // Bâton, batonnet baguette
  *(tab + 2) = 13; // Pétrification ou Métamorphose
  *(tab + 3) = 15; // Souffles
  *(tab + 4) = 12; // Sorts
  
  unsigned int cat;
  if (Niveau <= 5)
    cat = 0;
  else  if (Niveau <= 10)
    cat = 1;
  else  if (Niveau <= 15)
    cat = 2;
  else  if (Niveau <= 20)
    cat = 3;
  else
    cat = 4;

  *(tab + 0) -= cat;
  *(tab + 1) -= 2 * cat;
  *(tab + 2) -= 2 * cat;
  *(tab + 3) -= 2 * cat;
  *(tab + 4) -= 2 * cat;
}

/*
 * Retourne la compétence voulue.
 *
 * La variable Classe::elementaire permet d'afficher :
 *
 * DEBUG : la correspondance entre la compétence i et la position dans la
 * liste des compétences, ainsi que la distinction Compétence / Restriction.
 * @param i numéro de la compétence
 * @return la compétence
 */
// string Spec::getCompetence(const unsigned int& i) const
// {
//   Debug::empileNiveau( &elementaire );
//   //DebugLevelType etat_precedent(dout.getLevel());
//   //dout.setLevel(elementaire);
//    debug() <<  i << "-ème compétence => Compétence " << getComp(i) << endreq << flush;
//    if (getComp(i) < nbr_comp)
//      {
//        debug() << "=> compétence" << endreq;
//        Debug::depileNiveau();//dout.setLevel(etat_precedent);
//        return Comp[getComp(i)].Comp;
//      }
//    else
//      {
//        debug() << "=> restriction" << endreq;
//        Debug::depileNiveau();//dout.setLevel(etat_precedent);
//        return Restric[getComp(i)-nbr_comp].Comp;
//      }
// }

unsigned int Spec::calculeTAc0() const
{
  unsigned int mod_niveau((Niveau - 1) / 3);

  return 20 - mod_niveau;
}

void Spec::calculNivMag()
{
  if (Niveau < 11)
    Niveau_mag = (Niveau + 1) / 2;
  else if (Niveau == 11)
    Niveau_mag = 5;
  else if (Niveau < 20)
    Niveau_mag = Niveau / 2;
  else
    Niveau_mag = 9;
}

/**
 * Permet de récupérer l'ensemble de capacités raciales désiré.
 *
 * @param nbr numéro de l'ensemble voulu.
 * @return pointeur sur la première capacité de l'ensemble, ou le
 * pointeur nul si on accède à un ensemble inexistant.
 */
const vector<unsigned int>* Spec::getEnsembleCompetences(const unsigned int& nbr) const
{
  if ( nbr > nbr_spec )
    {
      warning() << "Tentative d'accéder à un ensemble inexistant!" << endreq;
      return 0;
    }
  return &ecoles_magie[ nbr ];
}

/**
 * Il faut ici regarder dans Cl_sorts pour savoir quels sont les sorts
 * contenus dans le Livre de Sorts du magicien.
 * 
 * Le tri se fait d'abord par Ecole, puis par Niveau et ensuite dans l'ordre
 * alphabétique.
 *
 * La variable Classe::fonction permet d'afficher :
 *
 * FUNC  : début et fin de l'exécution de la méthode
 *
 * DEBUG : écrasement du fichier, nombre de sorts, sort courant
 */
void Spec::ecrireSorts(const string& nom_fichier, const bool& ecrase) const
{
  Debug::empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Spec::ecrireSorts -> début" << endreq;
  ofstream sortie;
  if (ecrase)
    {
      debug() << "Ecrasement du fichier " << nom_fichier << endreq;
      sortie.open(nom_fichier.c_str());
    }
  else
    {
      sortie.open(nom_fichier.c_str(), ios::app);
      sortie << "\\newpage" << endl;
    }

  sortie << "\\section*{Livre de sorts - Mage}" << endl;

  unsigned int *vec = new unsigned int[Niveau_mag];

  nbrSort(vec, Niveau_mag);
  
  sortie << "\\begin{center}" << endl 
	 << "\\begin{tabular*}{10cm}{@{\\extracolsep{\\fill}} l r}"
	 << endl << "\\multicolumn{2}{c}{Nombre de sorts par jour} \\\\"
	 << "\\hline \\\\ \\vspace{1mm}" << endl;
  for (unsigned int i(0); i < Niveau_mag; i++)
    sortie << "Niveau " << i+1 << " & " << vec[i] << " \\\\" << endl;
  sortie << "\\end{tabular*}" << endl << "\\end{center}" << endl;

  unsigned int taille(getCombienSorts()), i, courant(10), niv_courant(10);
  string nom_ecoles[20] = {
    "Abjuration", "Alt\\'eration", "Conjuration - Convocation",
    "Divination","Enchantement - Charme", "Illusion - Fantasme",
    "Invocation - Evocation", "N\\'ecromancie", "Alchimie", "Artifices",
    "Dimension", "El\\'ementaire - Air", "El\\'ementaire - Eau",
    "El\\'ementaire - Feu", "El\\'ementaire - Terre", "Eurythmique",
    "Forces", "G\\'eom\\'etrie", "Mentalisme", "Ombres"};

  debug() << "nbr de sorts = " << taille << endl;

  for(i = 0; i < taille; i++)
    {
      if (Cl_sorts[i].getEcole() != courant)
	{
	  courant = Cl_sorts[i].getEcole();
	  niv_courant = Cl_sorts[i].getNiveau();
	  // courant garde en mémoire l'école courante
	  // niv_courant garde en mémoire le niveau courant
	  sortie << "\\subsection*{" << afficheAccent(nom_ecoles[courant])
		 << "}" << endl;
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}
      if (Cl_sorts[i].getNiveau() != niv_courant)
	{
	  niv_courant = Cl_sorts[i].getNiveau();
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}

      sortie << "\\input{../../Sorts-mage/"
	     << supprimeAccents(nom_ecoles[courant]) << "/sort_"
	     << niv_courant << "_" << Cl_sorts[i].getNumero() << ".inc.tex}" << endl;
    }

  sortie.close();
  func() << "Spec::ecrireSorts -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}

void Spec::nbrSort(unsigned int sorts[], const unsigned int& taille) const
{
  Debug::empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Spec::nbrSort -> début" << endreq;
  unsigned int i;
  unsigned int tmp[9];
  func() << "Niveau de magie = " << taille << endreq;

  for (i = 0; i < taille; i++)
    tmp[i] = 0;

  switch(Niveau)
    {
    case 1:
      tmp[0] = 1;
      break;
    case 2:
      tmp[0] = 2;
      break;
    case 3:
      tmp[0] = 2;
      tmp[1] = 1;
      break;
    case 4:
      tmp[0] = 3;
      tmp[1] = 2;
      break;
    case 5:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 1;
      break;
    case 6:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 2;
      break;
    case 7:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 2;
      tmp[3] = 1;
      break;
    case 8:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      break;
    case 9:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 1;
      break;
    case 10:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 2;
      break;
    case 11:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 3;
      tmp[4] = 3;
      break;
    case 12:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 1;
      break;
    case 13:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      break;
    case 14:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 15:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 16:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 2;
      tmp[7] = 1;
      break;
    case 17:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      break;
    case 18:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      tmp[8] = 1;
      break;
    case 19:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 1;
      break;
    default:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 4;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 2;
      break;
    }

  bool sort_sup(false);

  for (i = 0; i < getCombien(); i++)
    {
      if (Comp_classe[i] == 34)
	{
	  sort_sup = true;
	  break;
	}
    }

  if (sort_sup)
    {
      for (i = 0; i < Niveau_mag; i++)
	tmp[i]++;      
    }

  for (i = 0; i < Niveau_mag; i++)
    sorts[i] = tmp[i];
    

  func() << "Spec::nbrSort -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}

/**
 *
 * Permet de gérer l'ajout de sorts au livre du magicien
 *
 * La variable Classe::fonction permet d'afficher
 *
 * FUNC  : les messages de début - fin de la méthode
 *
 * LFUNC : les écoles auxquelles le Spécialiste a accès
 *
 * DEBUG : numéro du dernier sort, sort écrit, sorts triés
 */
void Spec::ajoutSorts()
{
  Debug::empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Spec::ajoutSorts -> début" << endreq;

  bool ecoles[20] = {false, false, false, false, false, false, false, false,
		     false, false, false, false, false, false, false, false,
		     false, false, false, false};
  unsigned int taille(getCombien()), i, tmp;
  bool sauter( false );

  for (i = 0; i < taille; i++)
    {
      tmp = Comp_classe[i];
      debug() << "tmp = " << tmp << endreq;
	if (tmp < 20)
	{
	  lfunc() << getCompetence(i, sauter) << " école" << endreq;
	  ecoles[tmp] = true;
	  linfo() << getCompetence(i, sauter) << " (" 
		  << i << ") oui" << endreq;
	}
	else
	  lfunc() << getCompetence(tmp, sauter) << " pas école"
		      << endreq;
    }

  unsigned int nbr, dernier;
  string ecole;


  debug() << "Nombre de sorts : " << getCombienSorts() << endreq;

  debug() << "Niveau magique = " << Niveau_mag << endreq;

  for (i = 0; i < 20; i++)
    {
      if (!ecoles[i])
	continue;
      blank() << Comp[i].Comp << endreq;
      for (unsigned int j(1); j <= Niveau_mag; j++)
	{
	  blank() << "Niveau " << j << " :" << endreq;
	  dernier = afficheSorts(i, j);

	  debug() << "dernier = " << dernier << endreq;
	
	  if (dernier > 0)
	    {
	      blank() << setw(2) << dernier + 1 << " Aucun" << endreq;
	      do
		{
		  nbr = demanderUnsignedBorne("Entrer nouveau sort : ", 1,
						dernier + 1);
		  if (nbr != dernier + 1)
		    {
		      debug() << "Ajout du sort " << Sort(i, j, nbr - 1)
				  << endreq;
		      Cl_sorts.push_back(Sort(i, j, nbr - 1));
		    }
		}
	      while(nbr != dernier + 1);
	    }
	}
    }

  if (getCombienSorts() == 0)
    return;

  debug() << "Nombre de sorts : " << getCombienSorts() << endreq;

  vector<Sort>::iterator Begin, End, it;
  Begin = Cl_sorts.begin();
  End   = Cl_sorts.end();

  for (it = Begin; it < End; it++)
    debug() << *it << endreq;

  sort(Begin, End);

  debug() << "Tri effectué" << endreq;

  unique(Begin, End);
  // for (it = ++Begin; it != End; it++)
  //   {
  //     if (*it == *(it - 1))
  // 	{
  // 	  lfunc() << "Même sort! " << *it << endreq;
  // 	  Cl_sorts.erase(it);
  // 	}
  //   }

  for (i = 0; i < Cl_sorts.size(); i++)
    debug() << Cl_sorts[i] << endreq;

  func() << "Spec::ajoutSorts -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}

/**
 * Permet de gérer les compétences martiales, càd lesquelles sont accessibles
 * à quel coût.
 *
 * Un Spécialiste peut prendre un arme réservée au Mage pour 3 pp, ou une arme
 * de Clerc ou de Voleur pour 5 pp et enfin une arme de Guerrier pour 6 pp.
 */
void Spec::getPrixAcces(map<string, unsigned int>*& Map) const
{
  Debug::empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Spec::getPrixAcces -> début" << endreq;

  map<string, unsigned int>::const_iterator mapIt, mapBegin(Map -> begin()),
    mapEnd(Map -> end());

  for (mapIt = mapBegin; mapIt != mapEnd; mapIt++)
    lfunc() << mapIt -> first << endreq;

  Map -> operator[]("Spécialiste") = 3;
  mapIt = Map -> find("Clerc");
  if ((mapIt != mapEnd && mapIt -> second > 5) || mapIt == mapEnd)
    Map -> operator[]("Clerc")    = 5;
  mapIt = Map -> find("Voleur");
  if ((mapIt != mapEnd && mapIt -> second > 5) || mapIt == mapEnd)
    Map -> operator[]("Voleur")   = 5;
  mapIt = Map -> find("Guerrier");
  if ((mapIt != mapEnd && mapIt -> second > 6) || mapIt == mapEnd)
    Map -> operator[]("Guerrier") = 6;
  
  func() << "Spec::getPrixAcces -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}

StatusCode Spec::prerequisOK(const string& race, const unsigned int& ensemble, const bool& complexe)
{
  Debug::empileNiveau( &elementaire );
  func() << "Spec::prerequisOK -> début" << endreq;

  StatusCode sc;

  if ( ! complexe )
    return sc;

  if ( RacesAdmises[ ensemble ] . find( race ) == RacesAdmises[ ensemble ] . end() )
    // Alors on n'a pas le droit!
    {
      error() << "Un " << race << " ne peut pas être "
	      << quel_spec[ ensemble ] . Capa << endreq;
      
      func() << "Spec::prerequisOK -> " << endreq;
      Debug::depileNiveau();

      return StatusCode( false, 0, 0, race + " interdit pour " + Type_classe );
    }

  vector< Prerequis >::const_iterator it, Begin( Limites[ensemble] . begin() ),
    End( Limites[ensemble] . end() );
  
  for (it = Begin; it != End; it++)
    {
      sc = it -> estOK( Traits );
      if ( ! sc )
	{
	  error() << Caracteristiques[ sc.valeur() ] << " doit être au minimum "
		  << sc.code() << ", valeur courante : " << Traits[ sc.valeur() ]
		  << endreq;
	  
	  func() << "Classe::prerequisOK -> " << endreq;
	  Debug::depileNiveau();
	  return sc;
	}
    }
  
  func() << "Spec::prerequisOK -> fin" << endreq;
  Debug::depileNiveau();

  return sc;
}
